﻿#!/usr/bin/env python
# 
# Asciidoc-book
# copyright 2010 http://www.liuzhongshu.com
#
import re, os, sys,time, shutil
import subprocess

#定义常量
CHAPTER_FILES = "preface;getting-started;faq"
RESOURCE_FILES = "images"
SINGLE_BOOK_FILE = "book.html"
BOOK_TITLE = "Asciidoc Book"


try:
    from optparse import OptionParser
except ImportError:
    try:
        from optik import OptionParser
    except ImportError:
        raise ImportError, 'Requires Python 2.3 or the Optik option parsing library.'

parser = OptionParser()
parser.add_option('-f', '--format', dest='format',default="help",
                  help='The output format, can be help, pdf, default is help')
parser.add_option('-c', '--chapters', dest='chapters',default=CHAPTER_FILES,
                  help='The chapter file names of the book, default is: preface;getting-started;faq')                  
parser.add_option('-r', '--resources', dest='resources',default=RESOURCE_FILES,
                  help='The resource files and directories, default is images')                  
parser.add_option('-i', '--input', dest='input', default="src",
                  help='The input chapter files directory, default is src.')
parser.add_option('-l', '--level', dest='level', type="int", default=3,
                  help='The toc level of the output, default is 3.')
parser.add_option('-o', '--output', dest='output', default=r"output",
                  help=r'The output directory, default is output')
parser.add_option('-a', '--anchor', dest='anchor', default=r"",
                  help=r'The output anchor map file, default is not generated')

(options, args) = parser.parse_args(sys.argv[1:])


class util:
    @staticmethod
    def quote(s):
        return '"'+s+'"'
        
    @staticmethod
    def copytree(src, dst, symlinks=False, ignore=None):
        names = os.listdir(src)
        if ignore is not None:
            ignored_names = ignore(src, names)
        else:
            ignored_names = set()
        
        #zhongshu: add this check to enable dst already existed, and remove some stupid exception checking
        if not os.path.isdir(dst):
            os.makedirs(dst)
        
        errors = []
        for name in names:
            if name in ignored_names:
                continue
            srcname = os.path.join(src, name)
            dstname = os.path.join(dst, name)
            if symlinks and os.path.islink(srcname):
                linkto = os.readlink(srcname)
                os.symlink(linkto, dstname)
            elif os.path.isdir(srcname):
                util.copytree(srcname, dstname, symlinks, ignore)
            else:
                try:
                    shutil.copy2(srcname, dstname)
                except Exception:
                    pass    
      
    @staticmethod
    def get_run_output(target, useCall=True, useShell=True, cwd=None):
        if useCall:
            target = "call " + target
        process = subprocess.Popen(target, shell=useShell, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=cwd)
        (stdoutput,erroutput) = process.communicate()
        return stdoutput

    @staticmethod
    def run(target, useCall=True, useShell=True, cwd=None):
        if useCall:
            target = "call " + target
        process = subprocess.Popen(target, shell=useShell, cwd=cwd)
        process.wait()
        return process.returncode
        
    @staticmethod
    def replaceFile(path, pattern, to):
        content = file(path, "rb").read()
        content = re.compile(pattern).sub(to,content)
        file(path, "wb").write(content)
        
class asciidoc_book:
    def main(self):
        if options.format == "help":
            self.make_help_book()
        elif options.format == "html":   
            self.make_html_book()
        elif options.format == "pdf":
            self.make_pdf_book()            
        else:
            raise Exception("Output format: " + options.format + " not valid.")    

    def check_path(self):
        if not os.path.isdir(options.output):
            os.makedirs(options.output)
            
        for res in options.resources.split(";"):
            src = os.path.join(options.input, res)
            dst = os.path.join(options.output, res)
            if os.path.isfile(src):
                shutil.copyfile(src, dst)
            elif os.path.isdir(src):
                util.copytree(src,dst)                
                    
    def make_html_book(self):
        content = ""
        for text in options.chapters.split(";"):
            source_file = os.path.join(options.input, text + ".txt")
            if text != "" and os.path.isfile(source_file):
                content += file(source_file, "rb").read()
                if not content.endswith("\r") and not content.endswith("\n"):
                    print "add new line"
                    content += "\r\n"
        
        single_text_file = os.path.join(options.output, "~book.txt")
        file(single_text_file, "wb").write(content)
        print "convert single html: " + SINGLE_BOOK_FILE + "..."
        util.run("asciidoc.py -a toc -n -o " +  os.path.join(options.output, SINGLE_BOOK_FILE) + " " + single_text_file)
        #os.remove(single_text_file)
        
    def make_help_book(self):
        self.check_path()
        tocs = "<div id=\"toc\">"+ BOOK_TITLE + "<ul>"
        anchors = {}
        chapters = options.chapters.split(";")
        #第一遍生成tocs, anchors, htmls
        for idx, text in enumerate(chapters):
            source_file = os.path.join(options.input, text + ".txt")
            target_file = os.path.join(options.output, text + ".html")

            print "convert " + source_file + "..."

            #取anchor检查
            for anchor_tag in re.findall(r"\[\[[a-zA-Z0-9_\-]+\]\]", file(source_file, "rb").read()):
                anchor = anchor_tag[2:-2].lower()
                if anchors.has_key(anchor):
                    raise Exception("Anchor " + anchor + " already used in" + anchors.get(anchor))
                else:
                    anchors[anchor] = text + ".html"    
            
            #转换成html
            util.run("asciidoc.py -n -o "  + target_file  + " " + source_file)
            
            #替换章节编号, 删除footer
            content = re.sub("(<[hH][2-9].*?>)1.",  "\\1 " + str(idx + 1) + ".", file(target_file, "rb").read())
            content = re.sub('<div id="footnotes">(.|\\n)*?</div>',  "", content)
            content = re.sub('<div id="footer">(.|\\n)*?</div>',  "", content)
            file(target_file, "wb").write(content)
            
            #生成目录                
            for _toc in re.findall("<[hH][2-" + str(options.level) + "].*?/[hH][2-" + str(options.level) + "]>", content):
                id = re.search("<[hH][2-" + str(options.level) + "]\\s+id=\"(.*?)\"", _toc).group(1)
                name = re.search("<[hH][2-" + str(options.level) + "].*?>(.*?)</[hH][2-" + str(options.level) + "]>", _toc).group(1)
                level = re.search("<[hH]([2-" + str(options.level) + "])", _toc).group(1)
                tocs = tocs + "<li class=\"level" + level + "\"><a href=\""+ text + ".html#" + id + "\">"+ name + "</a></li>"
                    
        tocs = tocs + "</ul></div>"
        
        #第二遍替换所有html的目录和css
        for text in chapters:
            selfpath = os.path.realpath(__file__)
            chapter_css = file(os.path.join(os.path.dirname(selfpath), "default.css"),"rb").read()
            target_file = os.path.join(options.output, text + ".html")
            content = re.sub("<div id=\"header\">(.|\\n)*?</div>", tocs , file(target_file, "rb").read())
            content = re.sub("<style type=\"text/css\">(.|\\n)*?</style>", chapter_css , content)
            content = re.sub("<script type=\"text/javascript\">(.|\\n)*?</script>", "", content)
            file(target_file, "wb").write(content)
        
        #生成index.html
        shutil.copyfile(os.path.join(options.output, chapters[0] + ".html"),
                        os.path.join(options.output, "index.html"))
        
        if options.anchor != "":    
            anchor_props = ""        
            for a in anchors.keys():
                anchor_props += a + "=" + anchors[a] + "\r\n"            
            file(os.path.join(options.output, options.anchor), "wb").write(anchor_props)
                
            
    def make_pdf_book(self):
        self.check_path()
        print "make pdf book.. waiting for implementatiton"            

if __name__ == "__main__":
    asciidoc_book().main()